package com.redis.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author： yu.Tan
 * @Date: 2020/9/1 10:14
 * @Description: redisTemplate.opsForList();//操作list
 * redisTemplate.opsForValue();//操作字符串
 * redisTemplate.opsForCluster();//集群时使用
 * redisTemplate.opsForGeo();//地理位置时使用
 * redisTemplate.opsForHash();//操作hash
 * redisTemplate.opsForSet();//操作set
 * redisTemplate.opsForZSet();//操作有序set
 */
@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 读取缓存
     */
    public String getKey(final String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 写入缓存
     */
    public Boolean setKey(final String key, String value) {
        Boolean result = false;

        try {
            redisTemplate.opsForValue().set(key, value);
            result = Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 设置key/value值，并且可以设置超时时间。
     */
    public Boolean setKey(final String key, String value, int time, TimeUnit unit) {
        Boolean result = false;

        try {
            redisTemplate.opsForValue().set(key, value, time, unit);
            result = Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 同时设置多个key/value
     */
    public Boolean multiSet(Map<String, String> map) {
        Boolean result = false;

        try {
            redisTemplate.opsForValue().multiSet(map);
            result = Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 同时获取多个key/value
     */
    public List<String> multiGet(Collection<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * 操作取号器
     */
    public long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 跟新缓存
     */
    public Boolean getAndSet(final String key, String value) {
        Boolean result = Boolean.FALSE;
        try {
            redisTemplate.opsForValue().set(key, value);
            result = Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除key
     */
    public Boolean delete(final String key) {
        Boolean result = Boolean.FALSE;
        try {
            redisTemplate.delete(key);
            result = Boolean.TRUE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 操作队列，在高并发的情况下，如果同时上千个线程同时操作数据库， 数据库很可能会因此而宕机。这个时候我们可以利用redis队列，进行排队依次写入数据库。
     * 利用lpush和rpop，可以形成一个queue。
     */

    public void lpush(String key, String value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    public List<String> range(String key, int start, int end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    public Object rpop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 有时候我们不光希望保存key/value， 也希望缓存某个对象，比如用户所有数据到redis。 我们可以使用Redis的Hash数据结构来缓存。
     */
    public void setHash(String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    public Object getHash(String key, String prop) {
        return redisTemplate.opsForHash().get(key, prop);
    }

    public Map getHashAll(String key) {
        Map map = new HashMap();
        map.put("keys", redisTemplate.opsForHash().keys(key));
        map.put("vals", redisTemplate.opsForHash().values(key));
        return map;
    }

    /**
     * 如果我们需要一个小型的消息中间件，可以选择redis的订阅/发布来实现。
     */

    public void publish(String channal ,Object obj) {
        redisTemplate.convertAndSend(channal,obj );
    }

}
